entMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="去除水印" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Xot-0B-lcT">
- <rect key="frame" x="200.5" y="15" width="62" height="18"/>
+ <rect key="frame" x="176.5" y="15" width="62" height="18"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
+ <accessibility key="accessibilityConfiguration">
+ <accessibilityTraits key="traits" image="YES"/>
+ </accessibility>
<constraints>
- <constraint firstItem="IpC-PG-FTb" firstAttribute="leading" secondItem="lCw-zE-NnH" secondAttribute="leading" id="AI8-0A-5NM"/>
<constraint firstItem="pvN-rn-4Jn" firstAttribute="centerY" secondItem="lCw-zE-NnH" secondAttribute="centerY" id="IiE-3R-qra"/>
- <constraint firstAttribute="trailing" secondItem="IpC-PG-FTb" secondAttribute="trailing" id="JXk-xw-Ijl"/>
<constraint firstItem="Xot-0B-lcT" firstAttribute="leading" secondItem="pvN-rn-4Jn" secondAttribute="trailing" constant="5" id="iEp-95-h2T"/>
<constraint firstItem="pvN-rn-4Jn" firstAttribute="centerX" secondItem="lCw-zE-NnH" secondAttribute="centerX" constant="-40" id="ldO-mF-P0P"/>
- <constraint firstAttribute="bottom" secondItem="IpC-PG-FTb" secondAttribute="bottom" id="w9Z-mh-Lbw"/>
- <constraint firstItem="IpC-PG-FTb" firstAttribute="top" secondItem="lCw-zE-NnH" secondAttribute="top" id="wZx-uT-kRL"/>
<constraint firstItem="Xot-0B-lcT" firstAttribute="centerY" secondItem="pvN-rn-4Jn" secondAttribute="centerY" id="z6Y-h0-ffK"/>
</constraints>
+ <connections>
+ <outletCollection property="gestureRecognizers" destination="thN-TP-atT" appends="YES" id="gKW-D0-5pd"/>
+ </connections>
</view>
</subviews>
<constraints>
@@ -648,54 +500,64 @@
<color key="backgroundColor" red="0.94117647059999998" green="0.94117647059999998" blue="0.94117647059999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<gestureRecognizers/>
<constraints>
- <constraint firstItem="9RM-c8-CL6" firstAttribute="top" secondItem="BJb-h6-o9s" secondAttribute="bottom" id="73f-0Y-3Vq"/>
- <constraint firstItem="9RM-c8-CL6" firstAttribute="top" secondItem="lID-7p-0oW" secondAttribute="bottom" constant="45" id="8XF-qX-tug"/>
- <constraint firstAttribute="trailing" secondItem="BJb-h6-o9s" secondAttribute="trailing" id="FVI-fa-ovF"/>
- <constraint firstAttribute="bottom" secondItem="M7B-fx-M7f" secondAttribute="bottom" id="HPO-e8-4k2"/>
- <constraint firstItem="BJb-h6-o9s" firstAttribute="leading" secondItem="DXj-L8-o9b" secondAttribute="leading" id="LUw-LA-s32"/>
- <constraint firstAttribute="trailing" secondItem="M7B-fx-M7f" secondAttribute="trailing" id="N1J-SK-PaC"/>
- <constraint firstItem="9RM-c8-CL6" firstAttribute="top" secondItem="n3n-4c-ZrJ" secondAttribute="bottom" id="WmR-iX-rxE"/>
- <constraint firstItem="lID-7p-0oW" firstAttribute="centerX" secondItem="DXj-L8-o9b" secondAttribute="centerX" id="X50-n0-wZy"/>
- <constraint firstItem="BJb-h6-o9s" firstAttribute="top" secondItem="aUY-hC-XIK" secondAttribute="bottom" id="YxH-gE-R4v"/>
- <constraint firstAttribute="trailing" secondItem="n3n-4c-ZrJ" secondAttribute="trailing" id="c7G-xk-PsT"/>
- <constraint firstItem="n3n-4c-ZrJ" firstAttribute="leading" secondItem="DXj-L8-o9b" secondAttribute="leading" id="cYR-vc-dTi"/>
- <constraint firstItem="M7B-fx-M7f" firstAttribute="leading" secondItem="DXj-L8-o9b" secondAttribute="leading" id="svX-zh-yc8"/>
+ <constraint firstItem="fD2-Ow-gtt" firstAttribute="leading" secondItem="9gv-8b-ehH" secondAttribute="leading" id="05m-kg-yB6"/>
+ <constraint firstItem="9gv-8b-ehH" firstAttribute="bottom" secondItem="lID-7p-0oW" secondAttribute="bottom" constant="45" id="8XF-qX-tug"/>
+ <constraint firstAttribute="bottom" secondItem="M7B-fx-M7f" secondAttribute="bottom" constant="-56" id="HPO-e8-4k2"/>
+ <constraint firstItem="fD2-Ow-gtt" firstAttribute="top" secondItem="9gv-8b-ehH" secondAttribute="top" id="IeE-A7-ZV9"/>
+ <constraint firstItem="9gv-8b-ehH" firstAttribute="trailing" secondItem="M7B-fx-M7f" secondAttribute="trailing" id="N1J-SK-PaC"/>
+ <constraint firstAttribute="bottom" secondItem="n3n-4c-ZrJ" secondAttribute="bottom" id="WmR-iX-rxE"/>
+ <constraint firstItem="lID-7p-0oW" firstAttribute="centerX" secondItem="9gv-8b-ehH" secondAttribute="centerX" id="X50-n0-wZy"/>
+ <constraint firstAttribute="bottom" secondItem="fD2-Ow-gtt" secondAttribute="bottom" id="XB5-IP-h70"/>
+ <constraint firstItem="9gv-8b-ehH" firstAttribute="trailing" secondItem="n3n-4c-ZrJ" secondAttribute="trailing" id="c7G-xk-PsT"/>
+ <constraint firstItem="n3n-4c-ZrJ" firstAttribute="leading" secondItem="9gv-8b-ehH" secondAttribute="leading" id="cYR-vc-dTi"/>
+ <constraint firstItem="9gv-8b-ehH" firstAttribute="trailing" secondItem="fD2-Ow-gtt" secondAttribute="trailing" id="riO-3O-KZ0"/>
+ <constraint firstItem="M7B-fx-M7f" firstAttribute="leading" secondItem="9gv-8b-ehH" secondAttribute="leading" id="svX-zh-yc8"/>
</constraints>
- <connections>
- <outletCollection property="gestureRecognizers" destination="thN-TP-atT" appends="YES" id="fm4-zR-Gbm"/>
- </connections>
+ <viewLayoutGuide key="safeArea" id="9gv-8b-ehH"/>
</view>
+ <size key="freeformSize" width="375" height="1000"/>
<connections>
<outlet property="buyView" destination="n3n-4c-ZrJ" id="SXL-nK-eIX"/>
+ <outlet property="commentCount" destination="cuT-s1-NnA" id="m50-cn-Kcn"/>
+ <outlet property="commentEditYConstraint" destination="HPO-e8-4k2" id="tfy-Rg-aiz"/>
+ <outlet property="commentEditingView" destination="M7B-fx-M7f" id="ZRf-mw-WVD"/>
<outlet property="commentHeight" destination="HPO-e8-4k2" id="gpG-te-dKf"/>
+ <outlet property="commentTableView" destination="fD2-Ow-gtt" id="jog-WM-p44"/>
<outlet property="commentTextField" destination="1va-ae-Juh" id="TpO-kE-PhT"/>
- <outlet property="commentView" destination="M7B-fx-M7f" id="c0Q-vg-7C9"/>
+ <outlet property="enterGroupView" destination="gSr-Cm-y1W" id="bNT-Z4-eOG"/>
+ <outlet property="groupAvatar" destination="nng-M9-7cj" id="Y42-Tc-QnV"/>
+ <outlet property="groupName" destination="XM7-FX-tOk" id="ifP-h1-72j"/>
+ <outlet property="photoCollectionView" destination="dtf-M8-otl" id="VlY-wa-ekc"/>
+ <outlet property="photoTime" destination="QpI-Mp-URP" id="rJM-TG-fZW"/>
<outlet property="sendBtn" destination="oef-gW-sEK" id="3RV-uD-3q1"/>
- <outlet property="shuiyinImage" destination="pvN-rn-4Jn" id="SOk-vE-uCT"/>
- <outlet property="shuiyinLabel" destination="Xot-0B-lcT" id="eWR-Rv-Fzl"/>
- <outlet property="tableView" destination="BJb-h6-o9s" id="XS2-bS-jiH"/>
- <outlet property="thumbupView" destination="lID-7p-0oW" id="nBh-5u-Utm"/>
- <outlet property="waterMarkView" destination="lCw-zE-NnH" id="CPm-lw-FQT"/>
+ <outlet property="thumbupCount" destination="h88-PP-cvG" id="hwu-eb-a1J"/>
+ <outlet property="thumbupView" destination="Zde-8U-5Bl" id="ceB-lf-AhY"/>
+ <outlet property="thumbupViewHeightConstraint" destination="fc8-6l-lEC" id="E8M-of-NHC"/>
+ <outlet property="userAvatar" destination="Zj6-ve-uzJ" id="3Un-We-QLK"/>
+ <outlet property="userName" destination="jmc-9F-Uzr" id="1Z5-wc-83i"/>
+ <outlet property="waterMarkImage" destination="pvN-rn-4Jn" id="TaO-CX-590"/>
+ <outlet property="waterMarkLabel" destination="Xot-0B-lcT" id="Jok-hr-Eeb"/>
+ <outlet property="waterMarkView" destination="lCw-zE-NnH" id="z8i-gh-ZRG"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="MFn-pn-5Jb" userLabel="First Responder" sceneMemberID="firstResponder"/>
- <tapGestureRecognizer id="thN-TP-atT">
+ <tapGestureRecognizer id="thN-TP-atT" userLabel="purchaseGestureRecognizer">
<connections>
- <action selector="ReturnKeyboard:" destination="qsT-Pc-Bhh" id="uVf-UL-SuP"/>
- <outlet property="delegate" destination="qsT-Pc-Bhh" id="vFS-jJ-MlO"/>
+ <action selector="purchase:" destination="qsT-Pc-Bhh" id="qjs-Ot-XwA"/>
+ </connections>
+ </tapGestureRecognizer>
+ <tapGestureRecognizer id="EHE-XX-kIE" userLabel="enterGroupGestureRecognizer">
+ <connections>
+ <action selector="enterGroup:" destination="qsT-Pc-Bhh" id="dZE-ok-iUM"/>
</connections>
</tapGestureRecognizer>
</objects>
- <point key="canvasLocation" x="-1927.2" y="1267.0164917541231"/>
+ <point key="canvasLocation" x="-1452" y="1137.9310344827586"/>
</scene>
<!--ShareController-->
<scene sceneID="UTe-rv-qoO">
<objects>
<viewController storyboardIdentifier="ShareController" automaticallyAdjustsScrollViewInsets="NO" id="KnW-jg-4H5" userLabel="ShareController" customClass="ShareController" customModule="Paiai_iOS" customModuleProvider="target" sceneMemberID="viewController">
- <layoutGuides>
- <viewControllerLayoutGuide type="top" id="hPQ-yS-v0d"/>
- <viewControllerLayoutGuide type="bottom" id="xwf-Eg-SuC"/>
- </layoutGuides>
<view key="view" contentMode="scaleToFill" id="rN5-Zb-vwm">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
@@ -795,10 +657,11 @@
</subviews>
<gestureRecognizers/>
<constraints>
- <constraint firstItem="xUW-ue-yp5" firstAttribute="leading" secondItem="rN5-Zb-vwm" secondAttribute="leading" id="Afy-jR-Jec"/>
- <constraint firstItem="xwf-Eg-SuC" firstAttribute="top" secondItem="xUW-ue-yp5" secondAttribute="bottom" constant="127" id="hco-RD-Kle"/>
- <constraint firstAttribute="trailing" secondItem="xUW-ue-yp5" secondAttribute="trailing" id="lAd-Wf-RcE"/>
+ <constraint firstItem="xUW-ue-yp5" firstAttribute="leading" secondItem="C6P-7J-fWs" secondAttribute="leading" id="Afy-jR-Jec"/>
+ <constraint firstItem="C6P-7J-fWs" firstAttribute="bottom" secondItem="xUW-ue-yp5" secondAttribute="bottom" constant="127" id="hco-RD-Kle"/>
+ <constraint firstItem="C6P-7J-fWs" firstAttribute="trailing" secondItem="xUW-ue-yp5" secondAttribute="trailing" id="lAd-Wf-RcE"/>
</constraints>
+ <viewLayoutGuide key="safeArea" id="C6P-7J-fWs"/>
</view>
<connections>
<outlet property="shareView" destination="xUW-ue-yp5" id="I5g-Zk-9uW"/>
@@ -806,22 +669,18 @@
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="9LO-35-FRH" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
- <point key="canvasLocation" x="649.60000000000002" y="1430.2848575712146"/>
+ <point key="canvasLocation" x="-513" y="1287"/>
</scene>
- <!--ShowFullPicController-->
+ <!--PhotoPreviewViewController-->
<scene sceneID="yhk-2u-fiu">
<objects>
- <viewController storyboardIdentifier="ShowFullPicController" automaticallyAdjustsScrollViewInsets="NO" id="p3y-A2-QU1" userLabel="ShowFullPicController" customClass="ShowFullPicController" customModule="PaiAi" sceneMemberID="viewController">
- <layoutGuides>
- <viewControllerLayoutGuide type="top" id="LdU-do-COB"/>
- <viewControllerLayoutGuide type="bottom" id="uHN-Ad-PoZ"/>
- </layoutGuides>
+ <viewController storyboardIdentifier="PhotoPreviewViewController" automaticallyAdjustsScrollViewInsets="NO" id="p3y-A2-QU1" userLabel="PhotoPreviewViewController" customClass="PhotoPreviewViewController" customModule="Paiai_iOS" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="MdC-Fu-zFL">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
- <collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" pagingEnabled="YES" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" indicatorStyle="white" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="cvI-jg-TrD">
- <rect key="frame" x="0.0" y="20" width="395" height="647"/>
+ <collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" pagingEnabled="YES" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" indicatorStyle="white" dataMode="prototypes" prefetchingEnabled="NO" translatesAutoresizingMaskIntoConstraints="NO" id="cvI-jg-TrD">
+ <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<collectionViewFlowLayout key="collectionViewLayout" scrollDirection="horizontal" minimumLineSpacing="0.0" minimumInteritemSpacing="0.0" id="nE7-Ce-1KB">
<size key="itemSize" width="237.5" height="357"/>
<size key="headerReferenceSize" width="0.0" height="0.0"/>
@@ -830,7 +689,7 @@
</collectionViewFlowLayout>
<cells>
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="imageCell" id="PAU-eQ-c9k" customClass="ImageCell" customModule="Paiai_iOS" customModuleProvider="target">
- <rect key="frame" x="0.0" y="145" width="237.5" height="357"/>
+ <rect key="frame" x="0.0" y="155" width="237.5" height="357"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="237.5" height="357"/>
@@ -856,35 +715,31 @@
</connections>
</collectionViewCell>
</cells>
- <connections>
- <outlet property="dataSource" destination="p3y-A2-QU1" id="gOQ-91-JoU"/>
- <outlet property="delegate" destination="p3y-A2-QU1" id="Woc-UQ-V73"/>
- </connections>
</collectionView>
- <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="BRP-J0-WGF">
+ <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="BRP-J0-WGF" userLabel="button group">
<rect key="frame" x="0.0" y="623" width="375" height="44"/>
<subviews>
- <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Q90-2h-mGx">
- <rect key="frame" x="231" y="-26" width="96" height="96"/>
- <state key="normal" image="大图模式-下载"/>
- <connections>
- <action selector="load" destination="p3y-A2-QU1" eventType="touchUpInside" id="tC2-9R-1be"/>
- </connections>
- </button>
- <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="2r6-s1-9be">
+ <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="2r6-s1-9be" userLabel="back">
<rect key="frame" x="43.5" y="-26" width="96" height="96"/>
- <state key="normal" image="back"/>
+ <state key="normal" image="navigation-back"/>
<connections>
<action selector="back" destination="p3y-A2-QU1" eventType="touchUpInside" id="xKk-c3-Iub"/>
</connections>
</button>
- <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="aOC-mu-785">
+ <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="aOC-mu-785" userLabel="rotate">
<rect key="frame" x="139.5" y="-26" width="96" height="96"/>
- <state key="normal" image="旋转"/>
+ <state key="normal" image="BTN-rotate"/>
<connections>
<action selector="rotateTheImage:" destination="p3y-A2-QU1" eventType="touchUpInside" id="LiB-TG-UYL"/>
</connections>
</button>
+ <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Q90-2h-mGx" userLabel="download">
+ <rect key="frame" x="231" y="-26" width="96" height="96"/>
+ <state key="normal" image="BTN-download"/>
+ <connections>
+ <action selector="download:" destination="p3y-A2-QU1" eventType="touchUpInside" id="cEE-Yt-FWf"/>
+ </connections>
+ </button>
</subviews>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.5" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
@@ -902,14 +757,15 @@
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
- <constraint firstItem="uHN-Ad-PoZ" firstAttribute="top" secondItem="cvI-jg-TrD" secondAttribute="bottom" id="F0H-Mg-CBe"/>
- <constraint firstItem="uHN-Ad-PoZ" firstAttribute="top" secondItem="BRP-J0-WGF" secondAttribute="bottom" id="HMX-tH-TKt"/>
- <constraint firstItem="cvI-jg-TrD" firstAttribute="top" secondItem="MdC-Fu-zFL" secondAttribute="topMargin" id="bET-rg-QJH"/>
- <constraint firstItem="cvI-jg-TrD" firstAttribute="leading" secondItem="MdC-Fu-zFL" secondAttribute="leading" id="bxo-Ri-B7l"/>
- <constraint firstAttribute="trailing" secondItem="BRP-J0-WGF" secondAttribute="trailing" id="es7-Qg-qLl"/>
- <constraint firstItem="BRP-J0-WGF" firstAttribute="leading" secondItem="MdC-Fu-zFL" secondAttribute="leading" id="nES-ms-zxG"/>
- <constraint firstAttribute="trailing" secondItem="cvI-jg-TrD" secondAttribute="trailing" constant="-20" id="y4O-SP-QE3"/>
+ <constraint firstAttribute="bottom" secondItem="cvI-jg-TrD" secondAttribute="bottom" id="F0H-Mg-CBe"/>
+ <constraint firstItem="pxb-BY-KAJ" firstAttribute="bottom" secondItem="BRP-J0-WGF" secondAttribute="bottom" id="HMX-tH-TKt"/>
+ <constraint firstItem="cvI-jg-TrD" firstAttribute="top" secondItem="MdC-Fu-zFL" secondAttribute="top" id="bET-rg-QJH"/>
+ <constraint firstItem="cvI-jg-TrD" firstAttribute="leading" secondItem="pxb-BY-KAJ" secondAttribute="leading" id="bxo-Ri-B7l"/>
+ <constraint firstItem="pxb-BY-KAJ" firstAttribute="trailing" secondItem="BRP-J0-WGF" secondAttribute="trailing" id="es7-Qg-qLl"/>
+ <constraint firstItem="BRP-J0-WGF" firstAttribute="leading" secondItem="pxb-BY-KAJ" secondAttribute="leading" id="nES-ms-zxG"/>
+ <constraint firstItem="pxb-BY-KAJ" firstAttribute="trailing" secondItem="cvI-jg-TrD" secondAttribute="trailing" id="y4O-SP-QE3"/>
</constraints>
+ <viewLayoutGuide key="safeArea" id="pxb-BY-KAJ"/>
</view>
<connections>
<outlet property="collectionView" destination="cvI-jg-TrD" id="1eT-ax-Cma"/>
@@ -921,23 +777,22 @@
</scene>
</scenes>
<resources>
- <image name="BTN-分享" width="138" height="138"/>
- <image name="BTN-评论" width="138" height="138"/>
- <image name="Oval 491" width="192" height="192"/>
- <image name="back" width="36" height="72"/>
- <image name="icon-记录" width="36" height="36"/>
- <image name="icon-评论" width="36" height="36"/>
- <image name="icon-赞" width="36" height="36"/>
- <image name="list-arrow" width="16" height="16"/>
+ <image name="BTN-comment" width="138" height="138"/>
+ <image name="BTN-download" width="96" height="96"/>
+ <image name="BTN-rotate" width="96" height="96"/>
+ <image name="BTN-share" width="138" height="138"/>
+ <image name="BTN-thumbup" width="192" height="192"/>
+ <image name="defaultAvatar" width="240" height="240"/>
+ <image name="icon-comment" width="36" height="36"/>
+ <image name="icon-thumbup" width="36" height="36"/>
+ <image name="icon-time" width="36" height="36"/>
+ <image name="list-arrow" width="24" height="36"/>
+ <image name="navigation-back" width="36" height="72"/>
<image name="分享-QQ" width="162" height="162"/>
<image name="分享-微信好友" width="162" height="162"/>
<image name="分享-微博" width="162" height="162"/>
<image name="分享-朋友圈" width="162" height="162"/>
- <image name="去除水印" width="8" height="144"/>
- <image name="大图模式-下载" width="96" height="96"/>
- <image name="旋转" width="96" height="96"/>
<image name="购买-去水印" width="96" height="96"/>
<image name="进入群" width="114" height="60"/>
- <image name="默认头像" width="80" height="80"/>
</resources>
</document>
@@ -1,5 +1,5 @@ |
||
1 | 1 |
// |
2 |
-// DetailCommentCell.swift |
|
2 |
+// PhotoDetailCommentCell.swift |
|
3 | 3 |
// PaiAi |
4 | 4 |
// |
5 | 5 |
// Created by zhengjianfei on 16/4/8. |
@@ -10,7 +10,7 @@ import UIKit |
||
10 | 10 |
import PaiaiDataKit |
11 | 11 |
import PaiaiUIKit |
12 | 12 |
|
13 |
-class DetailCommentCell: UITableViewCell { |
|
13 |
+class PhotoDetailCommentCell: UITableViewCell { |
|
14 | 14 |
|
15 | 15 |
// MARK: Storyboard property |
16 | 16 |
@IBOutlet weak var headImage: UIImageView! |
@@ -7,9 +7,57 @@ |
||
7 | 7 |
// |
8 | 8 |
|
9 | 9 |
import Foundation |
10 |
+import PaiaiDataKit |
|
11 |
+ |
|
12 |
+final class PhotoDetailCoordinator: Coordinator { |
|
13 |
+ let navigationController: UINavigationController |
|
14 |
+ let photoDetailViewController: PhotoDetailViewController |
|
15 |
+ let shareListViewModel: PhotoDetailListViewModel |
|
16 |
+ |
|
17 |
+ fileprivate var coordinators = [String: Coordinator]() |
|
18 |
+ |
|
19 |
+ init(_ photoDetailVC: PhotoDetailViewController, |
|
20 |
+ nav: UINavigationController, |
|
21 |
+ viewModel: PhotoDetailViewModel, |
|
22 |
+ listViewModel: PhotoDetailListViewModel) { |
|
23 |
+ photoDetailViewController = photoDetailVC |
|
24 |
+ shareListViewModel = listViewModel |
|
25 |
+ navigationController = nav |
|
26 |
+ photoDetailViewController.listViewModel = shareListViewModel |
|
27 |
+ photoDetailViewController.viewModel = viewModel |
|
28 |
+ |
|
29 |
+ viewModel.delegate = self |
|
30 |
+ shareListViewModel.synchronization = viewModel |
|
31 |
+ shareListViewModel.delegate = self |
|
32 |
+ } |
|
33 |
+ |
|
34 |
+ func start() { |
|
35 |
+ |
|
36 |
+ } |
|
37 |
+} |
|
38 |
+ |
|
39 |
+extension PhotoDetailCoordinator: PhotoDetailViewModelDelegate { |
|
40 |
+ func navigateToGroup(_ item: GroupItem) { |
|
41 |
+ let vc = GroupViewController.instantiate() |
|
42 |
+ vc.viewModel = GroupViewModel(groupItem: item) |
|
43 |
+ let coordinator = GroupCoordinator(vc, |
|
44 |
+ navigationController: navigationController) |
|
45 |
+ coordinators["group"] = coordinator |
|
46 |
+ |
|
47 |
+ navigationController.pushViewController(vc) |
|
48 |
+ } |
|
49 |
+} |
|
50 |
+ |
|
51 |
+extension PhotoDetailCoordinator: PhotoDetailListViewModelDelegate { |
|
52 |
+ func didSelected() { |
|
53 |
+ let vc = UIStoryboard.photoDetail.instantiateController(PhotoPreviewViewController.self) |
|
54 |
+ vc.viewModel = shareListViewModel |
|
55 |
+ navigationController.pushViewController(vc, animated: true) |
|
56 |
+ } |
|
57 |
+} |
|
10 | 58 |
|
11 | 59 |
extension UIStoryboard { |
12 | 60 |
static var photoDetail: UIStoryboard { |
13 |
- return UIStoryboard(name: "Detail", bundle: Bundle(identifier: "com.Paiai-iOS")) |
|
61 |
+ return UIStoryboard(name: "PhotoDetail", bundle: Bundle(identifier: "com.Paiai-iOS")) |
|
14 | 62 |
} |
15 | 63 |
} |
@@ -9,5 +9,5 @@ |
||
9 | 9 |
import UIKit |
10 | 10 |
|
11 | 11 |
class PhotoDetailImageCell: UICollectionViewCell { |
12 |
- |
|
12 |
+ @IBOutlet weak var imageView: UIImageView! |
|
13 | 13 |
} |
@@ -9,6 +9,7 @@ |
||
9 | 9 |
import UIKit |
10 | 10 |
import RxSwift |
11 | 11 |
import RxCocoa |
12 |
+import RxDataSources |
|
12 | 13 |
import PaiaiDataKit |
13 | 14 |
import PaiaiUIKit |
14 | 15 |
|
@@ -17,6 +18,7 @@ let kPhotographerMark = 1 |
||
17 | 18 |
|
18 | 19 |
final class PhotoDetailViewController: UIViewController { |
19 | 20 |
|
21 |
+ @IBOutlet weak var enterGroupView: UIView! |
|
20 | 22 |
@IBOutlet weak var groupAvatar: UIImageView! |
21 | 23 |
@IBOutlet weak var groupName: UILabel! |
22 | 24 |
|
@@ -30,409 +32,333 @@ final class PhotoDetailViewController: UIViewController { |
||
30 | 32 |
@IBOutlet weak var thumbupView: UIView! |
31 | 33 |
|
32 | 34 |
@IBOutlet weak var commentCount: UILabel! |
33 |
- @IBOutlet weak var tableView: UITableView! |
|
35 |
+ @IBOutlet weak var commentTableView: UITableView! |
|
34 | 36 |
|
35 |
- @IBOutlet weak var commentView: UIView! |
|
37 |
+ @IBOutlet weak var commentEditingView: UIView! |
|
36 | 38 |
@IBOutlet weak var commentHeight: NSLayoutConstraint! |
37 | 39 |
@IBOutlet weak var commentTextField: UITextField! |
38 | 40 |
@IBOutlet weak var sendBtn: UIButton! |
39 | 41 |
|
40 | 42 |
@IBOutlet weak var buyView: UIView! |
43 |
+ @IBOutlet weak var waterMarkView: UIView! |
|
41 | 44 |
@IBOutlet weak var waterMarkImage: UIImageView! |
42 | 45 |
@IBOutlet weak var waterMarkLabel: UILabel! |
43 |
- |
|
46 |
+ |
|
47 |
+ @IBOutlet weak var thumbupViewHeightConstraint: NSLayoutConstraint! |
|
48 |
+ @IBOutlet weak var commentEditYConstraint: NSLayoutConstraint! |
|
49 |
+ |
|
44 | 50 |
// MARK: data property |
45 | 51 |
var viewModel: PhotoDetailViewModel! |
46 |
- lazy var datas = [PhotoItem]() |
|
47 |
- lazy var currentPhotoIndex = 0 |
|
48 |
- var isHiddenEnterView = false |
|
52 |
+ var listViewModel: PhotoDetailListViewModel! |
|
53 |
+ |
|
49 | 54 |
let disposeBag = DisposeBag() |
50 |
- static let storyboardCtl = UIStoryboard.photoDetail.instantiateInitialViewController() as! PhotoDetailViewController |
|
51 | 55 |
|
52 | 56 |
// MARK: view function |
53 | 57 |
override func viewDidLoad() { |
54 | 58 |
super.viewDidLoad() |
55 |
-// detailPageViewModel.tipDelegate = self |
|
56 |
-// tableView.tableFooterView = UIView() |
|
57 |
- configureNotification() |
|
58 |
- |
|
59 |
- commentTextField.rx.text |
|
60 |
- .map {!($0?.isEmpty)!} |
|
61 |
- .bind(to: sendBtn.rx.isEnabled) |
|
62 |
- .disposed(by: disposeBag) |
|
59 |
+ binding() |
|
60 |
+ setup() |
|
61 |
+ } |
|
62 |
+ |
|
63 |
+ func setup() { |
|
64 |
+ setupCommentTextField() |
|
65 |
+ setupWaterMarkView() |
|
63 | 66 |
} |
64 | 67 |
|
65 | 68 |
func setupCommentTextField() { |
66 | 69 |
commentTextField.addLeftPadding(7) |
67 | 70 |
} |
71 |
+ |
|
72 |
+ func setupWaterMarkView() { |
|
73 |
+ guard let image = UIImage.PhotoDetail.purchaseBackground else { return } |
|
74 |
+ waterMarkView.backgroundColor = UIColor(patternImage: image) |
|
75 |
+ } |
|
68 | 76 |
|
69 | 77 |
override func viewWillAppear(_ animated: Bool) { |
70 | 78 |
super.viewWillAppear(true) |
71 |
-// titleWithbackBar = "详情" |
|
72 |
- navigationController?.isNavigationBarHidden = false |
|
73 |
-// refreshUI(index: currentPhotoIndex) |
|
74 |
- } |
|
75 |
- |
|
76 |
-// override func backToController() { |
|
77 |
-// navigationController?.popViewController(animated: true) |
|
78 |
-// if let last = navigationController?.viewControllers[(navigationController?.viewControllers.count)! - 1] as? HomeViewController { |
|
79 |
-//// last.mainViewModel.models.value = datas |
|
80 |
-// } |
|
81 |
-// |
|
82 |
-// if let last = navigationController?.viewControllers[(navigationController?.viewControllers.count)! - 1] as? GroupViewController { |
|
83 |
-//// last.MineGroupViewModel.models.value = datas |
|
84 |
-// } |
|
85 |
-// } |
|
86 |
- |
|
87 |
- func configureNotification() { |
|
88 |
- do { |
|
89 |
-// NotificationCenter.default.rx.notification(Notification.Name(rawValue: WXPayDidFinishNotification)).asObservable().subscribe { (notification) in |
|
90 |
-// FFToastView.showLoadingToast(inView: UIApplication.shared.keyWindow!, blockSuperView: true) |
|
91 |
-// self.detailPageViewModel.handleResult(errorCode: 0, success: {[weak self](PhotoItem) in |
|
92 |
-// if let weakself = self { |
|
93 |
-// weakself.datas[weakself.currentPhotoIndex].murl = PhotoItem.murl |
|
94 |
-// weakself.datas[weakself.currentPhotoIndex].rurl = PhotoItem.rurl |
|
95 |
-//// weakself.showBuyView() |
|
96 |
-// weakself.tableView.reloadRows(at: [IndexPath(item: 0, section: 1)], with: .none) |
|
97 |
-// let fullPicCtl = UIStoryboard.detailBoard.instantiateController(ShowFullPicController.self) |
|
98 |
-// fullPicCtl.datas = weakself.datas |
|
99 |
-// fullPicCtl.currentPhotoIndex = weakself.currentPhotoIndex |
|
100 |
-// fullPicCtl.showNomark = weakself.detailPageViewModel.watermarkPrice != -1 |
|
101 |
-// fullPicCtl.showHD = weakself.detailPageViewModel.hdPrice != -1 |
|
102 |
-// weakself.navigationController?.pushViewController(fullPicCtl, animated: true) |
|
103 |
-// } |
|
104 |
-// }) |
|
105 |
-// }.disposed(by: disposeBag) |
|
106 |
- } |
|
107 |
- do { |
|
108 |
-// NotificationCenter.default.rx.notification(Notification.Name.UIKeyboardWillShow) |
|
109 |
-// .asObservable() |
|
110 |
-// .subscribe({ (notification) in |
|
111 |
-// guard let info = notification.element?.userInfo, let avalue = info[UIKeyboardFrameEndUserInfoKey] else { |
|
112 |
-// return |
|
113 |
-// } |
|
114 |
-// |
|
115 |
-// let height = (avalue as AnyObject).cgRectValue.size.height |
|
116 |
-// self.returnKeyboarAction(notification.element!, height: height) |
|
117 |
-// }).disposed(by: disposeBag) |
|
118 |
- } |
|
119 |
- |
|
120 |
- do { |
|
121 |
- NotificationCenter.default.rx.notification(UIResponder.keyboardWillHideNotification) |
|
122 |
- .asObservable() |
|
123 |
- .subscribe({ (notification) in |
|
124 |
- self.returnKeyboarAction(notification.element!, height: 0) |
|
125 |
- }).disposed(by: disposeBag) |
|
126 |
- } |
|
127 |
- |
|
79 |
+ viewModel.viewWillAppear.accept(()) |
|
128 | 80 |
} |
81 |
+} |
|
129 | 82 |
|
130 |
- // MARK: refresh interface |
|
131 |
- func refreshUI(index: Int) { |
|
132 |
- currentPhotoIndex = index |
|
133 |
-// detailPageViewModel.currentPhoto = datas[index] |
|
134 |
- |
|
135 |
-// detailPageViewModel.fetchThumbup(success: {[weak self] in |
|
136 |
-// if let weakself = self { |
|
137 |
-// var model = weakself.datas[index] |
|
138 |
-// model.thumbup_num = weakself.detailPageViewModel.thumbups.count |
|
139 |
-// weakself.datas[index] = model |
|
140 |
-//// PhotoLocalStorage.instance.updateLocalData(PhotoItem: model) |
|
141 |
-// weakself.reloadSection(inter: 3) |
|
142 |
-// } |
|
143 |
-// }) |
|
144 |
-// detailPageViewModel.fetchComment(success: {[weak self] in |
|
145 |
-// if let weakself = self { |
|
146 |
-// |
|
147 |
-// var model = weakself.datas[index] |
|
148 |
-// model.comment_num = weakself.detailPageViewModel.comments.count |
|
149 |
-// weakself.datas[index] = model |
|
150 |
-//// PhotoLocalStorage.instance.updateLocalData(PhotoItem: model) |
|
151 |
-// weakself.reloadSection(inter: 4) |
|
152 |
-// } |
|
153 |
-// }) |
|
83 |
+//MARK textField delegate |
|
84 |
+extension PhotoDetailViewController: UIGestureRecognizerDelegate { |
|
85 |
+ // MARK: textField |
|
154 | 86 |
|
155 |
-// reloadSection(inter: 0) |
|
156 |
-// reloadSection(inter: 2) |
|
157 |
- showBuyView() |
|
87 |
+ func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool { |
|
88 |
+ return commentTextField.isFirstResponder |
|
158 | 89 |
} |
90 |
+ |
|
91 |
+} |
|
159 | 92 |
|
160 |
- func showBuyView() { |
|
161 |
-// if detailPageViewModel.currentPhoto.photo_from == kPhotographerMark && detailPageViewModel.currentPhoto.display_payment_btn == 1 { |
|
162 |
-// buyView.isHidden = false |
|
163 |
-// detailPageViewModel.hdPrice = -0.01 |
|
164 |
-// detailPageViewModel.watermarkPrice = -0.01 |
|
165 |
-// shuiyinLabel.text = !detailPageViewModel.currentPhoto.murl.isEmpty ? "查看无水印图" : "去除水印" |
|
166 |
-// shuiyinImage.isHidden = false |
|
167 |
-// } else { |
|
168 |
-// buyView.isHidden = true |
|
169 |
-// } |
|
170 |
- } |
|
171 | 93 |
|
172 |
- // MARK: Storyboard button function |
|
173 |
- @IBAction func HDPay(_ sender: UIButton) { |
|
174 |
-// detailPageViewModel.getHD (getPriceSuccess: { [weak self] (isExist) in |
|
175 |
-// if let weakself = self { |
|
176 |
-// if isExist { |
|
177 |
-// let fullPicCtl = UIStoryboard(name: "Detail", bundle: nil).instantiateController(ShowFullPicController.self) |
|
178 |
-// fullPicCtl.datas = [weakself.datas[weakself.currentPhotoIndex]] |
|
179 |
-// fullPicCtl.showNomark = true |
|
180 |
-// fullPicCtl.currentPhotoIndex = weakself.currentPhotoIndex |
|
181 |
-// weakself.navigationController?.pushViewController(fullPicCtl, animated: true) |
|
182 |
-// } else { |
|
183 |
-// } |
|
184 |
-// } |
|
185 |
-// }) |
|
94 |
+/// bind storyboard gesture action |
|
95 |
+extension PhotoDetailViewController { |
|
96 |
+ @IBAction func purchase(_ sender: UITapGestureRecognizer) { |
|
97 |
+ |
|
186 | 98 |
} |
187 |
- |
|
188 |
- @IBAction func waterMarkPay(_ sender: UIButton) { |
|
189 |
- |
|
190 |
-// detailPageViewModel.getWatermark (getPriceSuccess: { [weak self] (isExist) in |
|
191 |
-// if let weakself = self { |
|
192 |
-// if isExist { |
|
193 |
-// let fullPicCtl = UIStoryboard(name: "Detail", bundle: nil).instantiateController(ShowFullPicController.self) |
|
194 |
-// fullPicCtl.datas = weakself.datas |
|
195 |
-// fullPicCtl.showNomark = true |
|
196 |
-// fullPicCtl.currentPhotoIndex = weakself.currentPhotoIndex |
|
197 |
-// weakself.navigationController?.pushViewController(fullPicCtl, animated: true) |
|
198 |
-// } else { |
|
199 |
-// weakself.shuiyinImage.isHidden = true |
|
200 |
-// weakself.shuiyinLabel.text = "¥\((weakself.detailPageViewModel.watermarkPrice/100))" |
|
201 |
-// } |
|
202 |
-// } |
|
203 |
-// }) |
|
99 |
+ |
|
100 |
+ @IBAction func enterGroup(_ sender: UITapGestureRecognizer) { |
|
101 |
+ self.viewModel.navigateToGroup() |
|
204 | 102 |
} |
103 |
+} |
|
205 | 104 |
|
105 |
+/// bind storyboard button action |
|
106 |
+extension PhotoDetailViewController { |
|
206 | 107 |
@IBAction func share() { |
207 | 108 |
let ctl = UIStoryboard.photoDetail.instantiateController(ShareController.self) |
208 | 109 |
ctl.shareContent = "我使用拍爱分享了一张美图,你也快来试试吧" |
209 |
- ctl.shareImgUrlThumb = datas[currentPhotoIndex].photo_thumbnail_url |
|
210 |
- ctl.shareUrl = datas[currentPhotoIndex].photo_share_url |
|
110 |
+ // ctl.shareImgUrlThumb = datas[currentPhotoIndex].photo_thumbnail_url |
|
111 |
+ // ctl.shareUrl = datas[currentPhotoIndex].photo_share_url |
|
211 | 112 |
presentController(ctl) |
212 | 113 |
} |
213 |
- |
|
114 |
+ |
|
214 | 115 |
@IBAction func comment() { |
215 |
- commentView.isHidden = false |
|
216 | 116 |
commentTextField.becomeFirstResponder() |
117 |
+ |
|
217 | 118 |
} |
218 |
- |
|
119 |
+ |
|
219 | 120 |
@IBAction func sendComment() { |
220 |
- guard let text = commentTextField.text else { |
|
221 |
- return |
|
222 |
- } |
|
223 |
-// detailPageViewModel.sendComment(content: text, success: { [weak self] in |
|
224 |
-// if let weakself = self { |
|
225 |
-// weakself.commentTextField.text = "" |
|
226 |
-// weakself.commentTextField.resignFirstResponder() |
|
227 |
-// weakself.commentView.isHidden = true |
|
228 |
-// weakself.refreshUI(index: weakself.currentPhotoIndex) |
|
229 |
-// } |
|
230 |
-// }) |
|
121 |
+ guard let text = commentTextField.text else { return } |
|
122 |
+ |
|
123 |
+ viewModel.submitComment(text: text) |
|
124 |
+ commentTextField.resignFirstResponder() |
|
231 | 125 |
} |
232 |
- |
|
126 |
+ |
|
233 | 127 |
@IBAction func thumbup() { |
234 |
-// detailPageViewModel.sendThumbup(success: {[weak self] in |
|
235 |
-// if let weakself = self { |
|
236 |
-// weakself.refreshUI(index: weakself.currentPhotoIndex) |
|
237 |
-// } |
|
238 |
-// |
|
239 |
-// }) |
|
128 |
+ viewModel.submitThumbup() |
|
240 | 129 |
} |
130 |
+} |
|
241 | 131 |
|
242 |
- // MARK: custom function |
|
243 |
- func reloadSection(inter: Int) { |
|
244 |
- tableView.beginUpdates() |
|
245 |
- let indexSet = IndexSet(integer: inter) |
|
246 |
- tableView.reloadSections(indexSet, with: .none) |
|
247 |
- tableView.endUpdates() |
|
132 |
+/// bind rx |
|
133 |
+extension PhotoDetailViewController { |
|
134 |
+ |
|
135 |
+ var commentTableViewDataSource: RxTableViewSectionedAnimatedDataSource<AnimatableSectionModel<Int, PhotoCommentItem>> { |
|
136 |
+ return RxTableViewSectionedAnimatedDataSource<AnimatableSectionModel<Int, PhotoCommentItem>>(configureCell: { (dataSource, tableView, indexPath, item) in |
|
137 |
+ let cell = tableView.dequeueReusableCell(withIdentifier: "photoDetailCommentCell", for: indexPath) as! PhotoDetailCommentCell |
|
138 |
+ cell.setInfo(item) |
|
139 |
+ return cell |
|
140 |
+ }) |
|
248 | 141 |
} |
249 |
- |
|
250 |
- @objc func showThumps() { |
|
251 |
-// if detailPageViewModel.thumbupsCount > 0 { |
|
252 |
-// detailPageViewModel.thumbupsCount = 0 |
|
253 |
-// } else { |
|
254 |
-// detailPageViewModel.thumbupsCount = detailPageViewModel.thumbups.count |
|
255 |
-// } |
|
256 |
- reloadSection(inter: 3) |
|
257 |
- } |
|
258 |
- @objc func showComments() { |
|
259 |
-// if detailPageViewModel.commentsCount > 0 { |
|
260 |
-// detailPageViewModel.commentsCount = 0 |
|
261 |
-// } else { |
|
262 |
-// detailPageViewModel.commentsCount = detailPageViewModel.comments.count |
|
263 |
-// } |
|
264 |
- reloadSection(inter: 4) |
|
142 |
+ |
|
143 |
+ var photoCollectionViewDataSource: RxCollectionViewSectionedAnimatedDataSource<AnimatableSectionModel<Int, PhotoItem>> { |
|
144 |
+ return RxCollectionViewSectionedAnimatedDataSource<AnimatableSectionModel<Int, PhotoItem>>(configureCell: { (dataSource, collectionView, indexPath, item) in |
|
145 |
+ let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "photoDetailImageCell", for: indexPath) as! PhotoDetailImageCell |
|
146 |
+ cell.imageView.setImage(item.photo_thumbnail2_url, placeholder: UIImage.photoPlaceholder) |
|
147 |
+ return cell |
|
148 |
+ }) |
|
265 | 149 |
} |
266 |
- |
|
267 |
- @objc func loadReportController() { |
|
268 |
-// let ctl = UIStoryboard.photoDetail.instantiateController(ReportController.self) |
|
269 |
-// presentController(ctl) |
|
150 |
+ |
|
151 |
+ func binding() { |
|
152 |
+ bindEnterGroupViewHiddenState() |
|
153 |
+ bindViewModelToGroupName() |
|
154 |
+ bindViewModelToGroupAvatar() |
|
155 |
+ |
|
156 |
+ bindViewModelToUserName() |
|
157 |
+ bindgingViewModelToUserAvatar() |
|
158 |
+ |
|
159 |
+ bindViewModelToThumbupCount() |
|
160 |
+ bindViewModelToThumbupView() |
|
161 |
+ |
|
162 |
+ bindViewModelToCommentCount() |
|
163 |
+ bindViewModelToCommentTableView() |
|
164 |
+ |
|
165 |
+ bindBuyViewIsVisiable() |
|
166 |
+ |
|
167 |
+ bindCommentTextFieldToSendBtn() |
|
168 |
+ |
|
169 |
+ bindCollectionViewDelegate() |
|
170 |
+ bindCollectionViewSelected() |
|
171 |
+ bindCollectionViewToListViewModel() |
|
172 |
+ bindListViewModelToCollectionView() |
|
173 |
+ |
|
174 |
+ bindViewWillAppear() |
|
175 |
+ |
|
176 |
+ monitorKeyboardWillShow() |
|
177 |
+ monitorKeyboardWillHide() |
|
270 | 178 |
} |
271 |
- |
|
272 |
- func returnKeyboarAction(_ notification: Notification, height: CGFloat) { |
|
273 |
- guard let info = (notification as NSNotification).userInfo, let duration = info[UIResponder.keyboardAnimationDurationUserInfoKey] as? TimeInterval else { |
|
274 |
- return |
|
275 |
- } |
|
276 |
- |
|
277 |
- UIView.animate(withDuration: duration, animations: {() -> Void in |
|
278 |
- self.commentHeight.constant = height |
|
279 |
- self.commentView.superview!.layoutIfNeeded() |
|
280 |
- }) |
|
179 |
+ |
|
180 |
+ func bindEnterGroupViewHiddenState() { |
|
181 |
+ viewModel.isHiddenEnterGroupBtn.bind(to: enterGroupView.rx.isHidden).disposed(by: disposeBag) |
|
281 | 182 |
} |
282 |
- |
|
283 |
- // MARK: deinit |
|
284 |
- deinit { |
|
285 |
- NotificationCenter.default.removeObserver(self) |
|
183 |
+ |
|
184 |
+ func bindViewModelToGroupName() { |
|
185 |
+ viewModel.groupName.bind(to: groupName.rx.text).disposed(by: disposeBag) |
|
286 | 186 |
} |
287 |
- |
|
288 |
-} |
|
289 |
- |
|
290 |
-// MARK: custom delegate function |
|
291 |
-extension PhotoDetailViewController: CellDelegate { |
|
292 |
- func selectIndex(indexpath: IndexPath) { |
|
293 |
- let ctl = UIStoryboard.photoDetail.instantiateController(ShowFullPicController.self) |
|
294 |
- ctl.datas = datas |
|
295 |
- ctl.currentPhotoIndex = currentPhotoIndex |
|
296 |
- show(ctl, sender: nil) |
|
187 |
+ |
|
188 |
+ func bindViewModelToGroupAvatar() { |
|
189 |
+ viewModel.groupAvatar |
|
190 |
+ .subscribe(onNext: {[weak self] (avatar) in |
|
191 |
+ guard let `self` = self else { return } |
|
192 |
+ self.groupAvatar.setImage(avatar) |
|
193 |
+ }).disposed(by: disposeBag) |
|
297 | 194 |
} |
298 |
- |
|
299 |
- func returnCurrentIndex(index: Int) { |
|
300 |
- refreshUI(index: index) |
|
195 |
+ |
|
196 |
+ func bindgingViewModelToUserAvatar() { |
|
197 |
+ viewModel.userAvatar |
|
198 |
+ .subscribe(onNext: {[weak self] (avatar) in |
|
199 |
+ guard let `self` = self else { return } |
|
200 |
+ self.userAvatar.setImage(avatar) |
|
201 |
+ }).disposed(by: disposeBag) |
|
301 | 202 |
} |
302 |
- |
|
303 |
- func pushNext() { |
|
304 |
- let ctl = UIStoryboard.main.instantiateController(GroupViewController.self) |
|
305 |
- |
|
306 |
-// ctl.groupModel = GroupModel(map: Map(mappingType: .fromJSON, JSON: datas[currentPhotoIndex].toJSON())) |
|
307 |
- show(ctl, sender: nil) |
|
203 |
+ |
|
204 |
+ func bindViewModelToUserName() { |
|
205 |
+ viewModel.groupName.bind(to: userName.rx.text).disposed(by: disposeBag) |
|
308 | 206 |
} |
309 |
-} |
|
310 |
- |
|
311 |
-//MARK textField delegate |
|
312 |
-extension PhotoDetailViewController: UIGestureRecognizerDelegate { |
|
313 |
- // MARK: textField |
|
314 |
- |
|
315 |
- func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool { |
|
316 |
- return commentTextField.isFirstResponder |
|
207 |
+ |
|
208 |
+ func bindViewModelToPhotoTime() { |
|
209 |
+ viewModel.photoTime.bind(to: photoTime.rx.text).disposed(by: disposeBag) |
|
317 | 210 |
} |
318 |
- |
|
319 |
- @IBAction func ReturnKeyboard(_ sender: UITapGestureRecognizer) { |
|
320 |
- if !commentView.isHidden { |
|
321 |
- commentTextField.resignFirstResponder() |
|
322 |
- commentView.isHidden = true |
|
323 |
- } |
|
211 |
+ |
|
212 |
+ func bindViewModelToThumbupCount() { |
|
213 |
+ viewModel.thumbupCount.bind(to: thumbupCount.rx.text).disposed(by: disposeBag) |
|
324 | 214 |
} |
325 |
- |
|
326 |
-} |
|
327 |
- |
|
328 |
-// MARK: UITableView delegate |
|
329 |
-extension PhotoDetailViewController: UITableViewDataSource, UITableViewDelegate { |
|
330 |
- |
|
331 |
- func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { |
|
332 |
- if section == 3 { |
|
333 |
- let cell = tableView.dequeueReusableCell(withIdentifier: "thumbupHeadCell") |
|
334 |
- if let label = cell?.viewWithTag(1001) as? UILabel { |
|
335 |
-// label.text = "(\(detailPageViewModel.thumbups.count))" |
|
336 |
- } |
|
337 |
- if let button = cell?.viewWithTag(1011) as? UIButton { |
|
338 |
- button.addTarget(self, action: #selector(showThumps), for: .touchUpInside) |
|
339 |
- } |
|
340 |
- if let imageView = cell?.viewWithTag(1008) as? UIImageView { |
|
341 |
-// let imageName = detailPageViewModel.thumbupsCount <= 0 ? "收起" : "list-arrow" |
|
342 |
-// imageView.image = UIImage(named : imageName) |
|
343 |
- } |
|
344 |
- return cell?.contentView |
|
345 |
- } else if section == 4 { |
|
346 |
- let cell = tableView.dequeueReusableCell(withIdentifier: "comentHeadCell") |
|
347 |
- if let label = cell?.viewWithTag(1002) as? UILabel { |
|
348 |
-// label.text = "(\(detailPageViewModel.comments.count))" |
|
349 |
- } |
|
350 |
- if let button = cell?.viewWithTag(1012) as? UIButton { |
|
351 |
- button.addTarget(self, action: #selector(showComments), for: .touchUpInside) |
|
352 |
- } |
|
353 |
- if let imageView = cell?.viewWithTag(1009) as? UIImageView { |
|
354 |
-// let imageName = detailPageViewModel.commentsCount <= 0 ? "收起" : "list-arrow" |
|
355 |
-// imageView.image = UIImage(named : imageName) |
|
356 |
- } |
|
357 |
- return cell?.contentView |
|
358 |
- } |
|
359 |
- return nil |
|
215 |
+ |
|
216 |
+ func bindViewModelToThumbupView() { |
|
217 |
+ viewModel.thumbupItems |
|
218 |
+ .asDriver(onErrorJustReturn: []) |
|
219 |
+ .drive(onNext: { [weak self] (items) in |
|
220 |
+ self?.setupThumbupView(items: items) |
|
221 |
+ }).disposed(by: disposeBag) |
|
360 | 222 |
} |
361 |
- |
|
362 |
- func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { |
|
363 |
- if section == 3 || section == 4 { |
|
364 |
- return 44 |
|
365 |
- } |
|
366 |
- return 0 |
|
223 |
+ |
|
224 |
+ func bindViewModelToCommentCount() { |
|
225 |
+ viewModel.commentCount.bind(to: commentCount.rx.text).disposed(by: disposeBag) |
|
367 | 226 |
} |
368 |
- |
|
369 |
- func numberOfSections(in tableView: UITableView) -> Int { |
|
370 |
- return 0 |
|
227 |
+ |
|
228 |
+ func bindViewModelToCommentTableView() { |
|
229 |
+ viewModel.commentItems |
|
230 |
+ .bind(to: commentTableView.rx.items(dataSource: commentTableViewDataSource)) |
|
231 |
+ .disposed(by: disposeBag) |
|
371 | 232 |
} |
372 |
- |
|
373 |
- func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { |
|
374 |
-// if section == 3 { |
|
375 |
-// return detailPageViewModel.thumbupsCount > 0 ? 1 : 0 |
|
376 |
-// } else if section == 4 { |
|
377 |
-// return detailPageViewModel.commentsCount |
|
378 |
-// } |
|
379 |
- return 0 |
|
233 |
+ |
|
234 |
+ func bindBuyViewIsVisiable() { |
|
235 |
+ viewModel.canBuy.map { !$0 }.bind(to: buyView.rx.isHidden).disposed(by: disposeBag) |
|
380 | 236 |
} |
381 |
- |
|
382 |
- func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { |
|
383 |
- if indexPath.section == 0 { |
|
384 |
- let cell = tableView.dequeueReusableCell(withIdentifier: "headCell", for: indexPath) as! DetailPageHeadCell |
|
385 |
- cell.enterView.isHidden = isHiddenEnterView |
|
386 |
-// cell.setInfo(datas[currentPhotoIndex]) |
|
387 |
- cell.delegate = self |
|
388 |
- if let reportBtn = cell.viewWithTag(40001) as? UIButton { |
|
389 |
- |
|
390 |
- reportBtn.addTarget(self, action: #selector(loadReportController), for: .touchUpInside) |
|
391 |
-// reportBtn.isHidden = !(UserDefaults.Account.bool(forKey: .isAudit)) |
|
392 |
- } |
|
393 |
- return cell |
|
394 |
- } else if indexPath.section == 1 { |
|
395 |
- let cell = tableView.dequeueReusableCell(withIdentifier: "detailPagePhotoCell", for: indexPath) as! DetailPagePhotoCell |
|
396 |
-// cell.datas = datas |
|
397 |
-// cell.currentPhotoIndex = currentPhotoIndex |
|
398 |
- cell.delegate = self |
|
399 |
- cell.first = true |
|
400 |
- cell.collectionView.reloadData() |
|
401 |
- return cell |
|
402 |
- } else if indexPath.section == 2 { |
|
403 |
- let cell = tableView.dequeueReusableCell(withIdentifier: "nameCell", for: indexPath) as! DetailPageNameCell |
|
404 |
-// cell.setInfo(datas[currentPhotoIndex]) |
|
405 |
- return cell |
|
406 |
- } else if indexPath.section == 3 { |
|
407 |
- let cell = tableView.dequeueReusableCell(withIdentifier: "thumbupCell", for: indexPath) as! DetailthumbupImagesCell |
|
408 |
-// if detailPageViewModel.thumbups.count > 0 { |
|
409 |
-// let headers = detailPageViewModel.thumbups.map {$0.avatar} |
|
410 |
-// cell.setInfo(content: headers) |
|
411 |
-// } |
|
412 |
- return cell |
|
413 |
- } else { |
|
414 |
- let cell = tableView.dequeueReusableCell(withIdentifier: "comentCell", for: indexPath) as! DetailCommentCell |
|
415 |
-// cell.setInfo(detailPageViewModel.comments[indexPath.row]) |
|
416 |
- return cell |
|
417 |
- } |
|
237 |
+ |
|
238 |
+ func bindCommentTextFieldToSendBtn() { |
|
239 |
+ commentTextField.rx.text |
|
240 |
+ .map { !($0?.isEmpty)! } |
|
241 |
+ .bind(to: sendBtn.rx.isEnabled) |
|
242 |
+ .disposed(by: disposeBag) |
|
243 |
+ } |
|
244 |
+ |
|
245 |
+ func bindCollectionViewDelegate() { |
|
246 |
+ photoCollectionView.rx.setDelegate(self).disposed(by: disposeBag) |
|
247 |
+ |
|
248 |
+ } |
|
249 |
+ |
|
250 |
+ func bindListViewModelToCollectionView() { |
|
251 |
+ listViewModel.content |
|
252 |
+ .bind(to: photoCollectionView.rx.items(dataSource: photoCollectionViewDataSource)) |
|
253 |
+ .disposed(by: disposeBag) |
|
254 |
+ } |
|
255 |
+ |
|
256 |
+ func bindCollectionViewToListViewModel() { |
|
257 |
+ photoCollectionView.rx.willDisplayCell |
|
258 |
+ .asDriver() |
|
259 |
+ .drive(onNext: { [unowned self] in |
|
260 |
+ self.listViewModel.willShow(index: $0.at.row) |
|
261 |
+ }) |
|
262 |
+ .disposed(by: disposeBag) |
|
263 |
+ } |
|
264 |
+ |
|
265 |
+ func bindCollectionViewSelected() { |
|
266 |
+ photoCollectionView.rx.itemSelected |
|
267 |
+ .asDriver(onErrorJustReturn: IndexPath(item: 0, section: 0)) |
|
268 |
+ .drive(onNext: { [unowned self] _ in self.listViewModel.didSelected() }) |
|
269 |
+ .disposed(by: disposeBag) |
|
270 |
+ } |
|
271 |
+ |
|
272 |
+ func bindViewWillAppear() { |
|
273 |
+ viewModel.viewWillAppear |
|
274 |
+ .asDriver() |
|
275 |
+ .drive(onNext: { [unowned self] _ in |
|
276 |
+ self.photoCollectionView.scrollToItem(at: IndexPath(item: self.listViewModel.currIndex, section: 0), at: .right, animated: false) |
|
277 |
+ }) |
|
278 |
+ .disposed(by: disposeBag) |
|
418 | 279 |
} |
280 |
+ |
|
281 |
+ func monitorKeyboardWillShow() { |
|
282 |
+ NotificationCenter.default.rx |
|
283 |
+ .notification(UIResponder.keyboardWillShowNotification) |
|
284 |
+ .takeUntil(self.rx.deallocated) |
|
285 |
+ .subscribe { [unowned self] notification in |
|
286 |
+ guard let userInfo = notification.element?.userInfo, |
|
287 |
+ let keyboardFrame = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect, |
|
288 |
+ let timeInterval = userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? TimeInterval, |
|
289 |
+ let curve = userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? Int |
|
290 |
+ else { return } |
|
291 |
+ UIView.setAnimationCurve(UIView.AnimationCurve(rawValue: curve) ?? .linear) |
|
292 |
+ UIView.animate(withDuration: timeInterval, animations: { |
|
293 |
+ self.commentEditYConstraint.constant = keyboardFrame.height |
|
294 |
+ self.view.layoutIfNeeded() |
|
295 |
+ }) |
|
296 |
+ }.disposed(by: disposeBag) |
|
297 |
+ } |
|
298 |
+ |
|
299 |
+ func monitorKeyboardWillHide() { |
|
300 |
+ NotificationCenter.default.rx |
|
301 |
+ .notification(UIResponder.keyboardWillHideNotification) |
|
302 |
+ .takeUntil(self.rx.deallocated) |
|
303 |
+ .subscribe { [unowned self] notification in |
|
304 |
+ guard let userInfo = notification.element?.userInfo, |
|
305 |
+ let timeInterval = userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? TimeInterval, |
|
306 |
+ let curve = userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? Int |
|
307 |
+ else { return } |
|
308 |
+ UIView.setAnimationCurve(UIView.AnimationCurve(rawValue: curve) ?? .linear) |
|
309 |
+ UIView.animate(withDuration: timeInterval, animations: { |
|
310 |
+ self.commentEditYConstraint.constant = -56 |
|
311 |
+ self.view.layoutIfNeeded() |
|
312 |
+ }) |
|
313 |
+ self.commentTextField.clear() |
|
314 |
+ }.disposed(by: disposeBag) |
|
315 |
+ } |
|
316 |
+} |
|
419 | 317 |
|
420 |
- func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { |
|
421 |
- if indexPath.section == 0 { |
|
422 |
- return 48 |
|
423 |
- } else if indexPath.section == 1 { |
|
424 |
- return 360 |
|
425 |
- } else if indexPath.section == 2 { |
|
426 |
- return 36 |
|
427 |
- } else if indexPath.section == 3 { |
|
428 |
- return 40 |
|
429 |
- } else { |
|
430 |
-// return 40 + detailPageViewModel.comments[indexPath.row].cellHeigth |
|
431 |
- return 40 |
|
318 |
+extension PhotoDetailViewController { |
|
319 |
+ func setupThumbupView(items: [PhotoThumbupUserItem]) { |
|
320 |
+ thumbupView.subviews.forEach { $0.removeFromSuperview() } |
|
321 |
+ |
|
322 |
+ let row = (Int(kScreenWidth) - 6) / 34 |
|
323 |
+ var topConstraint: CGFloat = 6 |
|
324 |
+ var last: UIImageView? |
|
325 |
+ |
|
326 |
+ for (index, item) in items.enumerated() { |
|
327 |
+ let imageView = UIImageView() |
|
328 |
+ imageView.cornerRadius = 5 |
|
329 |
+ imageView.translatesAutoresizingMaskIntoConstraints = false |
|
330 |
+ imageView.setImage(item.avatar, placeholder: UIImage.defaultAvatar) |
|
331 |
+ thumbupView.addSubview(imageView) |
|
332 |
+ |
|
333 |
+ if index % row == 0 && index != 0 { |
|
334 |
+ topConstraint += 28 + 6 |
|
335 |
+ last = nil |
|
336 |
+ } |
|
337 |
+ |
|
338 |
+ NSLayoutConstraint.activate([ |
|
339 |
+ imageView.widthAnchor.constraint(equalToConstant: 28), |
|
340 |
+ imageView.heightAnchor.constraint(equalToConstant: 28), |
|
341 |
+ imageView.topAnchor.constraint(equalTo: thumbupView.topAnchor, constant: topConstraint), |
|
342 |
+ imageView.leadingAnchor.constraint(equalTo: last?.trailingAnchor ?? thumbupView.leadingAnchor, constant: 6) |
|
343 |
+ ]) |
|
344 |
+ |
|
345 |
+ last = imageView |
|
432 | 346 |
} |
347 |
+ thumbupViewHeightConstraint.constant = items.isEmpty ? 1 : topConstraint + 34 |
|
348 |
+ commentTableView.tableHeaderView?.height = 532 + thumbupViewHeightConstraint.constant |
|
433 | 349 |
} |
434 | 350 |
} |
435 | 351 |
|
436 |
-extension PhotoDetailViewController { |
|
352 |
+extension PhotoDetailViewController: UICollectionViewDelegateFlowLayout { |
|
353 |
+ func collectionView(_ collectionView: UICollectionView, |
|
354 |
+ layout collectionViewLayout: UICollectionViewLayout, |
|
355 |
+ sizeForItemAt indexPath: IndexPath) -> CGSize { |
|
356 |
+ return CGSize(width: kScreenWidth, height: 359) |
|
357 |
+ } |
|
437 | 358 |
|
359 |
+ func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { |
|
360 |
+ return 0 |
|
361 |
+ } |
|
438 | 362 |
} |
363 |
+ |
|
364 |
+extension PhotoDetailViewController: NavigationBackViewController {} |
@@ -1,5 +1,5 @@ |
||
1 | 1 |
// |
2 |
-// ShowFullPicController.swift |
|
2 |
+// PhotoPreviewViewController.swift |
|
3 | 3 |
// PaiAi |
4 | 4 |
// |
5 | 5 |
// Created by zhengjianfei on 16/4/9. |
@@ -9,49 +9,104 @@ |
||
9 | 9 |
import UIKit |
10 | 10 |
import PaiaiDataKit |
11 | 11 |
import PaiaiUIKit |
12 |
+import RxCocoa |
|
13 |
+import RxSwift |
|
14 |
+import RxDataSources |
|
12 | 15 |
|
13 |
-final class ShowFullPicController: UIViewController { |
|
16 |
+final class PhotoPreviewViewController: UIViewController { |
|
14 | 17 |
|
15 |
- // MARK: Storyboard property |
|
18 |
+ /// MARK: Storyboard property |
|
16 | 19 |
@IBOutlet weak var collectionView: UICollectionView! |
17 |
-// @IBOutlet weak var progressView: FFProgress! |
|
18 |
- // MARK: parameter property |
|
19 |
- lazy var datas = [PhotoItem]() |
|
20 |
- lazy var currentPhotoIndex = 0 |
|
21 |
- lazy var firstLayout = true |
|
22 |
- lazy var currentPageIndex = 0 |
|
23 |
- lazy var showNomark = false |
|
24 |
- lazy var showHD = false |
|
25 |
- |
|
26 |
- var shufflingImage = [String]() |
|
27 |
- |
|
28 |
- // MARK: Controller fucntion |
|
20 |
+ var viewModel: PhotoDetailListViewModel! |
|
21 |
+ var disposeBag = DisposeBag() |
|
22 |
+ |
|
23 |
+ override var prefersStatusBarHidden: Bool { |
|
24 |
+ return true |
|
25 |
+ } |
|
26 |
+ |
|
29 | 27 |
override func viewDidLoad() { |
30 | 28 |
super.viewDidLoad() |
31 |
- navigationController?.isNavigationBarHidden = true |
|
32 |
-// titleWithbackBar = "" |
|
33 |
- |
|
34 |
- } |
|
35 |
- |
|
36 |
- override func viewDidLayoutSubviews() { |
|
37 |
- if firstLayout { |
|
38 |
- collectionView.contentOffset = CGPoint(x: (CGFloat(currentPhotoIndex) * (collectionView.width)), y: 0) |
|
39 |
- firstLayout = false |
|
29 |
+ binding() |
|
30 |
+ scrollToSpecifiedImage() |
|
31 |
+ navigationController?.setNavigationBarHidden(true, animated: true) |
|
32 |
+ |
|
33 |
+ } |
|
34 |
+ |
|
35 |
+ func scrollToSpecifiedImage() { |
|
36 |
+ collectionView.layoutIfNeeded() |
|
37 |
+ collectionView.scrollToItem(at: IndexPath(item: viewModel.currIndex, section: 0), at: .right, animated: false) |
|
38 |
+ } |
|
39 |
+ |
|
40 |
+ override func viewDidAppear(_ animated: Bool) { |
|
41 |
+ super.viewWillAppear(animated) |
|
42 |
+ bindCollectionViewToViewModel() |
|
43 |
+ } |
|
44 |
+ |
|
45 |
+ override func viewWillDisappear(_ animated: Bool) { |
|
46 |
+ super.viewWillDisappear(animated) |
|
47 |
+ navigationController?.setNavigationBarHidden(false, animated: true) |
|
48 |
+ } |
|
49 |
+ |
|
50 |
+ @IBAction func download(_ sender: UIButton) { |
|
51 |
+ guard let cell = collectionView.cellForItem(at: IndexPath(item: viewModel.currIndex, section: 0)) as? ImageCell, |
|
52 |
+ let image = cell.photoImage.image else { |
|
53 |
+ // FFToastView.showToast(inView: view, withText: "未检测到图片") |
|
54 |
+ return |
|
40 | 55 |
} |
41 |
- super.viewDidLayoutSubviews() |
|
56 |
+ |
|
57 |
+ UIImageWriteToSavedPhotosAlbum(image, self, #selector(image(_:didFinishSavingWithError:contextInfo:)), nil) |
|
42 | 58 |
} |
59 |
+ |
|
60 |
+ @objc func image(_ image: UIImage?, didFinishSavingWithError error: NSError?, contextInfo info: UnsafeMutableRawPointer) { |
|
61 |
+ if error != nil { |
|
62 |
+ // FFToastView.showToast(inView: view, withText: "保存图片失败") |
|
63 |
+ } else { |
|
64 |
+ // FFToastView.showImageToast(inView: view, withText: "已保存图片到相册", withImage: "提示弹窗-勾") |
|
65 |
+ } |
|
66 |
+ } |
|
67 |
+} |
|
68 |
+ |
|
69 |
+/// binding |
|
70 |
+extension PhotoPreviewViewController { |
|
71 |
+ |
|
72 |
+ var dataSource: RxCollectionViewSectionedAnimatedDataSource<AnimatableSectionModel<Int, PhotoItem>> { |
|
73 |
+ return RxCollectionViewSectionedAnimatedDataSource<AnimatableSectionModel<Int, PhotoItem>>(configureCell: { (dataSource, collectionView, indexPath, item) in |
|
74 |
+ let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "imageCell", for: indexPath) as! ImageCell |
|
75 |
+ cell.setModel(url: item.murl.isEmpty ? item.photo_url : item.murl) |
|
76 |
+ return cell |
|
77 |
+ }) |
|
78 |
+ } |
|
79 |
+ |
|
80 |
+ func binding() { |
|
81 |
+ bindViewModelToCollectionView() |
|
82 |
+ bindCollectionViewDelegate() |
|
83 |
+ } |
|
84 |
+ |
|
85 |
+ func bindViewModelToCollectionView() { |
|
86 |
+ viewModel.content |
|
87 |
+ .bind(to: collectionView.rx.items(dataSource: dataSource)) |
|
88 |
+ .disposed(by: disposeBag) |
|
89 |
+ } |
|
90 |
+ |
|
91 |
+ func bindCollectionViewDelegate() { |
|
92 |
+ collectionView.rx.setDelegate(self).disposed(by: disposeBag) |
|
93 |
+ } |
|
94 |
+ |
|
95 |
+ func bindCollectionViewToViewModel() { |
|
96 |
+ collectionView.rx.willDisplayCell |
|
97 |
+ .asDriver() |
|
98 |
+ .drive(onNext: { [unowned self] in self.viewModel.willShow(index: $0.at.row) }) |
|
99 |
+ .disposed(by: disposeBag) |
|
100 |
+ } |
|
101 |
+} |
|
43 | 102 |
|
44 |
- // MARK: Storyboard button function |
|
103 |
+/// storyboard button action |
|
104 |
+extension PhotoPreviewViewController { |
|
45 | 105 |
@IBAction func back() { |
46 |
- _ = navigationController?.popViewController(animated: true) |
|
47 |
- guard let ctl = navigationController?.viewControllers.last as? PhotoDetailViewController else { |
|
48 |
- return |
|
49 |
- } |
|
50 |
-// ctl.currentPhotoIndex = currentPageIndex |
|
51 |
-// ctl.tableView.reloadData() |
|
106 |
+ navigationController?.popViewController(animated: true) |
|
52 | 107 |
} |
53 | 108 |
@IBAction func rotateTheImage(_ sender: UIButton) { |
54 |
- guard let cell = collectionView.cellForItem(at: IndexPath(item: currentPageIndex, section: 0)) as? ImageCell else { |
|
109 |
+ guard let cell = collectionView.cellForItem(at: IndexPath(item: viewModel.currIndex, section: 0)) as? ImageCell else { |
|
55 | 110 |
return |
56 | 111 |
} |
57 | 112 |
UIView.beginAnimations("image.rotate", context: nil) |
@@ -71,54 +126,14 @@ final class ShowFullPicController: UIViewController { |
||
71 | 126 |
} |
72 | 127 |
} |
73 | 128 |
} |
129 |
+ |
|
74 | 130 |
|
75 |
- @IBAction func load() { |
|
76 |
- guard let cell = collectionView.cellForItem(at: IndexPath(item: currentPageIndex, section: 0)) as? ImageCell else { |
|
77 |
-// FFToastView.showToast(inView: view, withText: "未检测到图片") |
|
78 |
- return |
|
79 |
- } |
|
80 |
- guard let image = cell.photoImage.image else { |
|
81 |
-// FFToastView.showToast(inView: view, withText: "未检测到图片") |
|
82 |
- return |
|
83 |
- } |
|
84 |
- UIImageWriteToSavedPhotosAlbum(image, self, #selector(image(_:didFinishSavingWithError:contextInfo:)), nil) |
|
85 |
- } |
|
86 |
- |
|
87 |
- @objc func image(_ image: UIImage?, didFinishSavingWithError error: NSError?, contextInfo info: UnsafeMutableRawPointer) { |
|
88 |
- if error != nil { |
|
89 |
-// FFToastView.showToast(inView: view, withText: "保存图片失败") |
|
90 |
- } else { |
|
91 |
-// FFToastView.showImageToast(inView: view, withText: "已保存图片到相册", withImage: "提示弹窗-勾") |
|
92 |
- } |
|
93 |
- |
|
94 |
- } |
|
95 | 131 |
} |
96 | 132 |
|
97 | 133 |
// MARK: UICollectionView delegate |
98 |
-extension ShowFullPicController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { |
|
99 |
- |
|
100 |
- func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { |
|
101 |
- return shufflingImage.count > datas.count ? shufflingImage.count : datas.count |
|
102 |
- } |
|
103 |
- |
|
104 |
- func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { |
|
105 |
- let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "imageCell", for: indexPath) as! ImageCell |
|
106 |
- if shufflingImage.count <= 0 { |
|
107 |
- let data = datas[indexPath.item] |
|
108 |
- let urlStr = data.murl.isEmpty ? data.photo_url : data.murl |
|
109 |
- cell.setModel(url: urlStr) |
|
110 |
- } else { |
|
111 |
- cell.setModel(url: shufflingImage[indexPath.row]) |
|
112 |
- } |
|
113 |
- return cell |
|
114 |
- } |
|
134 |
+extension PhotoPreviewViewController: UICollectionViewDelegateFlowLayout { |
|
115 | 135 |
|
116 | 136 |
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { |
117 | 137 |
return CGSize(width: collectionView.width, height: collectionView.height - 20) |
118 | 138 |
} |
119 |
- |
|
120 |
- func scrollViewDidScroll(_ scrollView: UIScrollView) { |
|
121 |
- let page = Int(scrollView.contentOffset.x / (collectionView.width)) |
|
122 |
- currentPageIndex = page |
|
123 |
- } |
|
124 | 139 |
} |
@@ -9,13 +9,21 @@ |
||
9 | 9 |
import UIKit |
10 | 10 |
|
11 | 11 |
class ShareView: UIView { |
12 |
+ |
|
13 |
+} |
|
14 |
+ |
|
12 | 15 |
|
13 |
- /* |
|
14 |
- // Only override draw() if you perform custom drawing. |
|
15 |
- // An empty implementation adversely affects performance during animation. |
|
16 |
- override func draw(_ rect: CGRect) { |
|
17 |
- // Drawing code |
|
18 |
- } |
|
19 |
- */ |
|
20 | 16 |
|
17 |
+extension ShareView { |
|
18 |
+ |
|
19 |
+ func activateConstraints() { |
|
20 |
+ |
|
21 |
+ } |
|
22 |
+ |
|
23 |
+ func activateConstraintsShareView() { |
|
24 |
+ guard let superView = superview else { return } |
|
25 |
+ |
|
26 |
+ self.translatesAutoresizingMaskIntoConstraints = false |
|
27 |
+ |
|
28 |
+ } |
|
21 | 29 |
} |
@@ -1,15 +0,0 @@ |
||
1 |
-#!/bin/bash |
|
2 |
- |
|
3 |
-xcrun simctl shutdown all |
|
4 |
- |
|
5 |
-path=$(find ~/Library/Developer/Xcode/DerivedData/Paiai-*/Build/Products/Debug-iphonesimulator -name "Paiai.app" | head -n 1) |
|
6 |
-echo "${path}" |
|
7 |
- |
|
8 |
-filename=MultiSimConfig.txt |
|
9 |
-grep -v '^#' $filename | while read -r line |
|
10 |
-do |
|
11 |
- echo $line |
|
12 |
- xcrun instruments -w "$line" |
|
13 |
- xcrun simctl install booted $path |
|
14 |
- xcrun simctl launch booted com.Paiai.Paiai |
|
15 |
-done |